<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
</head>
<body>
<script>
// 下面，我们来构建一个父类构造器Shpae();
function shape(id) {
	this.id = id;
}
shape.prototype.name = 'shape';
shape.prototype.toString = function() {
	return this.name;
}

// 现在我们来定义Triangle()构造器，在其中通过apply()方法来调用shape()构造器，并将相关的this值和其他一些参数传递该方法
function Triangle() {
	shape.apply(this, arguments);
}

Triangle.prototype.name = 'Triangle';

// 注意，这里无论是triangle还是shape都在其各自的原型中添加额外的属性
// 我们来测试一下，先创建一个triangle对象
var t = new Triangle(101);
console.log(t.name);

// 这里新的trangle对象继承了其父对象的id属性，但他并没有基础功能父对象原型中的其他任何东西
console.log(t.id);
console.log(t.toString());

// 之所以triangle对象中不包含shape的原型属性，是因为我们从来没有调用New shape()创建任何一个实例，自然其原型也从来没有被用到。这点很容易做到，例如在本章中最初的那个演示中，我们可以对triangle()构造器进行如下重定义
function Triangle() {
	shape.apply(this, arguments);
}

Triangle.prototype = new shape();
Triangle.prototype.name = 'Triangle';

// 这种继承模式中，父对象的属性是子对象自身属性的身份来重建的。这也体现了构造器借用法的一个大优势：当我们创建一个继承于数组或者其他对象类型的子对象时，将获得一个完完全全的新值(不是一个引用)，对他做任何修改都不会影响到其父对象

// 但这种模式也有缺点，因为这种情况下父对象的构造器往往会被调用两次：一次发生在通过apply()方法继承其自身属性时，而另一个则发生在通过new操作符继承其原型时。这样一来，父对象的自身属性事实上被继承了两次。下面我们做一个演示
function shape(id) {
	this.id = id;
}
function Triangle() {
	shape.apply(this, arguments);
}
Triangle.prototype = new shape(10);

// 然后，我们新建一个实例
var t = new Triangle(202);
console.log(t.id);

// 对象中有一个自身属性id，但他并非来自原型链，我们可以执行如下验证
console.log(t.__proto__.id);
console.log(delete t.id);
console.log(t.id);

// 借用构造器与原型复制
// 对于这种由于构造器的双重调用而带来的重复执行问题，实际上是很容易更正的。我们可以在父对象上调用apply()方法，已获得其全部的自身属性，然后再用一个简单的迭代器对其原型属性进行逐项拷贝
function shape(id) {
	this.id = id;
}
shape.prototype.name = 'shape';
shape.prototype.toString = function() {
	return this.name;
}
function Triangle() {
	shape.apply(this, arguments);
}
function extend2(Child, Parent) {
	var p = Parent.prototype;
	var c = Child.prototype;
	for(var i in p){
		c[i] = p[i];
	}
	c.uber = p;
}
extend2(Triangle, shape);
Triangle.prototype.name = 'Triangle';

// 测试一下
var t = new Triangle(101);
console.log(t.toString());
console.log(t.id);

// 这样一来，双重继承就不见了
console.log(typeof t.__proto__.id);

// 如果有必要的话，extend2()还可以访问对象的uber属性
console.log(t.uber.name);
</script>
</body>
</html>